package com.xdf.ecommerce.service.async;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.base.Stopwatch;
import com.xdf.ecommerce.constant.GoodsConstant;
import com.xdf.ecommerce.entity.EcommerceGoods;
import com.xdf.ecommerce.dao.EcommerceGoodsMapper;
import com.xdf.ecommerce.goods.GoodsInfo;
import com.xdf.ecommerce.goods.SimpleGoodsInfo;
import com.xdf.ecommerce.service.IGoodsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.IterableUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author chanchaw
 * @create 2025-10-28 8:04
 */
@RequiredArgsConstructor
@Slf4j
@Service
@Transactional
public class AsyncServiceImpl implements IAsyncService{
    private final IGoodsService goodsService;
    private final StringRedisTemplate redisTemplate;

    /**
     * 使用异步的方式更新商品信息：
     * 1. 将商品信息保存到数据表
     * 2. 更新商品缓存
     * @param goodsInfoList
     * @param taskId
     */
    @Async("getAsyncExecutor") // 使用自定义线程池
    @Override
    public void asyncGoodsInfo(List<GoodsInfo> goodsInfoList, String taskId) {
        log.info("开始执行异步任务，taskId:[{}]", taskId);
        Stopwatch stopwatch = Stopwatch.createStarted();
        boolean isIllegal = false;

        // 将商品信息字段 joint 在一起，用来判断你是否存在重复
        Set<String> goodsJointInfos = new HashSet<>(goodsInfoList.size());
        // 过滤出来的，可以入库的商品信息（规则按照自己的业务需求自定义）
        List<GoodsInfo> filteredGoodsInfo = new ArrayList<>(goodsInfoList.size());
        // 遍历检测参数是否合法，判定当前请求是否合法
        for(GoodsInfo goods:goodsInfoList){
            if(goods.getPrice() <= 0 || goods.getSupply() <= 0){
                log.info("商品信息无效：[{}]", JSON.toJSONString(goods));
                continue;
            }

//            String jointInfo = String.format("s%,s%,s%", goods.getGoodsCategory(),goods.getBrandCategory(),goods.getGoodsName());
            String jointInfo = goods.getGoodsCategory() + "," + goods.getBrandCategory() + "," + goods.getGoodsName();
            if(goodsJointInfos.contains(jointInfo)) isIllegal = true;
            goodsJointInfos.add(jointInfo);
            filteredGoodsInfo.add(goods);
        }
        if(isIllegal || CollectionUtil.isEmpty(goodsInfoList)){
            stopwatch.stop();
            log.warn("没有更新任何商品信息:[{}]", JSON.toJSONString(filteredGoodsInfo));
            log.info("更新商品信息结束:[{}ms]", stopwatch.elapsed(TimeUnit.MILLISECONDS));
            return;
        }

        List<EcommerceGoods> ecommerceGoodsList = filteredGoodsInfo.stream().map(EcommerceGoods::to).collect(Collectors.toList());
        List<EcommerceGoods> targetGoods = new ArrayList<>(ecommerceGoodsList.size());
        ecommerceGoodsList.forEach(g -> {
            if(null != goodsService.findByGoodsNameAndMultCategory(g.getGoodsCategory(),g.getBrandCategory(),g.getGoodsName())) return;
            targetGoods.add(g);
        });

        // 商品信息入库
        List<EcommerceGoods> savedGoods = IterableUtils.toList(goodsService.insertBatch(targetGoods));
        stopwatch.stop();
        log.info("已写入数据库商品信息 [{}] 个，耗时 [{}ms]，即将同步给 redis", savedGoods.size(),stopwatch.elapsed(TimeUnit.MILLISECONDS));

        stopwatch.start();
        saveNewGoodsInfo2Redis(savedGoods);
        stopwatch.stop();
        log.info("同步给redis耗时 [{}ms]", stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    private void saveNewGoodsInfo2Redis(List<EcommerceGoods> goods){
        if(null == goods || goods.size() == 0) return;
        List<SimpleGoodsInfo> simpleGoodsInfos = goods.stream().map(EcommerceGoods::toSimple).collect(Collectors.toList());
        Map<String,String> id2JsonObject = new HashMap<>(simpleGoodsInfos.size());
        simpleGoodsInfos.forEach(item -> id2JsonObject.put(item.getId().toString(), JSON.toJSONString(item)));
        redisTemplate.opsForHash().putAll(GoodsConstant.ECOMMERCE_GOODS_DICT_KEY, id2JsonObject);// 向redis写入数据
    }
}
